/*
 * ============================================================================
 *
 *       Filename:  net.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2014年08月20日 14时25分36秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  jianxi sun (jianxi), ycsunjane@gmail.com
 *   Organization:  
 *
 * ============================================================================
 */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#include "thread.h"
#include "sockarr.h"
#include "aphash.h"
#include "message.h"
#include "dllayer.h"
#include "netlayer.h"
#include "system.h"
#include "arg.h"
#include "msg.h"
#include "chap.h"

static int net_dllrecv(void *arg)
{
	struct message_t *msg;
	msg = safe_malloc(sizeof(struct message_t) 
		+ DLL_PKT_DATALEN);
	msg->data = (char *)msg + sizeof(struct message_t); 

	int rcvlen;
	rcvlen = dll_rcv(msg->data, DLL_PKT_DATALEN);
	if(rcvlen < (int)sizeof(struct ethhdr)) {
		free(msg);
		return -1;
	}
	msg->len = rcvlen;

	sys_debug("datalink layer recive a packet\n");
	sys_debug("RECV: len: %d\n", rcvlen);
	pr_pkt(msg->data, rcvlen);

	struct msg_head_t *head;
	struct ap_hash_t *aphash;

	head = (struct msg_head_t *)(msg->data);
	aphash = hash_ap(&head->smac[0]);
	aphash->ts = time(NULL);

	msg->proto = MSG_PROTO_ETH; 
	message_insert(aphash, msg);
	return 0;
}

/* pthread recv netlayer */
static int net_netrcv(void *arg)
{
	struct sockarr_t *sockarr = arg;
	unsigned int events = sockarr->bakevent;
	int clisock = sockarr->sock;

	/* tcp lost */
	if(events & EPOLLRDHUP ||
		events & EPOLLERR ||
		events & EPOLLHUP) {
		sys_debug("Epool get err: %s(%d)\n", 
			strerror(errno), errno);
		sockarr_delete(sockarr, 0);
		return -1;
	}

	sys_debug("net layer recive a packet\n");

	struct nettcp_t tcp;
	struct message_t *msg;
	msg = safe_malloc(sizeof(struct message_t));
	tcp.sock = clisock;
	if(tcp_rcv(&tcp, &msg->data, &msg->len) < 0) {
		sockarr_delete(sockarr, 0);
		free(msg);
		return -1;
	}

	struct ap_hash_t *aphash;
	struct msg_head_t *head;
	head = (struct msg_head_t *)(msg->data);
	aphash = hash_ap(&head->smac[0]);
	aphash->ap.sock = clisock;
	aphash->ap.netrandom = 0;
	aphash->ts = time(NULL);

	msg->proto = MSG_PROTO_TCP;
	message_insert(aphash, msg);
	return 0;
}

/* pthread broadcast */
static void *net_dllbrd(void *arg)
{
	int brdlen = sizeof(struct msg_ac_brd_t);
	struct msg_ac_brd_t *reqbuf;
	reqbuf = safe_malloc(brdlen);

	while(1) {
		gconf.chaprandom = chap_get_random();
		sys_debug("Send a broadcast probe msg, random: %x (next %d second later)\n", 
			gconf.chaprandom, args_info.brditv_arg);

		fill_msg_header(&reqbuf->header, MSG_AC_BRD, 
			&gconf.acuuid[0], gconf.chaprandom);

		/* first broad cast packet, there is no need calculate chap */

		sys_debug("SEND: size: %d\n", brdlen);
		pr_pkt(reqbuf, brdlen);
		dll_brdcast((char *)reqbuf, brdlen);
		sleep(args_info.brditv_arg);
	}
	return NULL;
}

static void *net_listen(void *arg)
{
	int ret;
	struct nettcp_t tcplisten;
	tcplisten.addr.sin_family = AF_INET;
	tcplisten.addr.sin_addr.s_addr = htonl(INADDR_ANY);
	tcplisten.addr.sin_port = htons(args_info.port_arg);
	ret = tcp_listen(&tcplisten);
	if(ret < 0) {
		sys_err("Create listen tcp failed\n");
		exit(-1);
	}

	while(1) {
		tcp_accept(&tcplisten, net_netrcv);
	}
}

void net_init()
{
	int sock;

	/* init epoll */
	sockarr_init();

	/* init dll, add dllrcv in epoll */
	dll_init(&args_info.nic_arg[0], &sock, NULL, NULL);
	sockarr_insert(sock, net_dllrecv, NULL);

	/* create pthread recv msg */
	pthread_create_detach(sockarr_recv, NULL);
	sys_info(" > Create pthread sockarr_recv\n");

	/* create pthread tcp listen */
	pthread_create_detach(net_listen, NULL);
	sys_info(" > Create pthread tcp listen\n");

	/* create pthread broadcast ac probe packet */
	pthread_create_detach(net_dllbrd, NULL);
	sys_info(" > Create pthread broadcast dllayer\n");

	sys_info("MODULE: net init success\n");
}

